/*
Copyright (C) 2008  Jitu Das

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#define PURPLE_PLUGINS

#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <xmmsclient/xmmsclient.h>
#include <xmmsclient/xmmsclient-glib.h>

#include "plugin.h"
#include "notify.h"
#include "account.h"
#include "savedstatuses.h"
#include "status.h"
#include "signals.h"
#include "core.h"
#include "version.h"
#include "debug.h"

#define PLUGIN_ID "core-r2jitu-xmms2_pidgin"

PurplePlugin *xmms2_pidgin_plugin = NULL;
xmmsc_connection_t *xmms2conn = NULL;
PurpleSavedStatus *original_savedstatus = NULL;
unsigned int play_status;
gboolean display_song;
gboolean xmms2_connected = FALSE;
unsigned int current_song_id = 0;

void update_song_idchange_cb (xmmsc_result_t *result, void *userdata);
void xmms2_status_cb (xmmsc_result_t *result, void *userdata);
void info_changed_cb (xmmsc_result_t *result, void *userdata);
void unset_status(void);
void set_savedstatus(GString *str);
static gboolean xmms2_connect(void);

static void quitting_cb(void *data);
static void status_changed_cb(PurpleAccount *account, PurpleStatus *old, PurpleStatus *new, gpointer data);

void
unset_status(void) {
	PurpleSavedStatus *current_savedstatus = purple_savedstatus_get_current();
	if (strcmp("XMMS2", purple_savedstatus_get_title(current_savedstatus))) {
		original_savedstatus = current_savedstatus;
		purple_debug_info(PLUGIN_ID, "unset_status: new original savedstatus %s %d\n", purple_savedstatus_get_title(original_savedstatus), purple_savedstatus_get_type(original_savedstatus));
		return;
	}
	if (!original_savedstatus)
		original_savedstatus = purple_savedstatus_new(NULL, purple_savedstatus_get_type(current_savedstatus));
	purple_savedstatus_activate(original_savedstatus);
	purple_debug_info(PLUGIN_ID, "unsetted status\n");
}

void
set_savedstatus(GString *str) {
	PurpleSavedStatus *savedstatus = NULL, *current_savedstatus = purple_savedstatus_get_current();
	
	if (!(savedstatus = purple_savedstatus_find("XMMS2")))
		savedstatus = purple_savedstatus_new("XMMS2", purple_savedstatus_get_type(current_savedstatus));
	if (strcmp("XMMS2", purple_savedstatus_get_title(current_savedstatus))) {
		original_savedstatus = current_savedstatus;
		purple_savedstatus_set_type(savedstatus, purple_savedstatus_get_type(current_savedstatus));
		purple_debug_info(PLUGIN_ID, "new original savedstatus %s %d\n", purple_savedstatus_get_title(original_savedstatus), purple_savedstatus_get_type(original_savedstatus));
	}
	purple_debug_info(PLUGIN_ID, "previous savedstatus %s %d\n", purple_savedstatus_get_title(current_savedstatus), purple_savedstatus_get_type(current_savedstatus));
	if (purple_savedstatus_get_message(original_savedstatus)) {
		g_string_prepend(str, " :: ");
		g_string_prepend(str, purple_savedstatus_get_message(original_savedstatus));
	}
	purple_savedstatus_set_message(savedstatus, str->str);
	if (play_status == 1) purple_savedstatus_activate(savedstatus);
}

void
update_song_idchange_cb (xmmsc_result_t *result, void *userdata)
{
	char *title, *artist, *album;
	GString *msgstr = NULL;
	xmmsc_result_t *res = NULL;
	
	if (!display_song) return;
	
	if (!xmmsc_result_get_uint (result, &current_song_id)) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Could not retrieve current song (update_song_idchange_cb)", "Please make sure XMMS2 is playing");
		return;
	}
	
	purple_debug_info(PLUGIN_ID, "Current song id: %d\n", current_song_id);
	res = xmmsc_medialib_get_info (xmms2conn, current_song_id);
	xmmsc_result_wait (res);
	if (!res) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Could not retrieve current song (update_song_idchange_cb)", "Please make sure XMMS2 is playing");
		return;
	}
	xmmsc_result_get_dict_entry_string (res, "artist", &artist);
	xmmsc_result_get_dict_entry_string (res, "album", &album);
	xmmsc_result_get_dict_entry_string (res, "title", &title);
	
	msgstr = g_string_new("");
	g_string_append_printf(msgstr, "Listening to ");
	if (title) g_string_append_printf(msgstr, "%s", title);
	else g_string_append_printf(msgstr, "a song");
	if (artist) g_string_append_printf(msgstr, " by %s", artist);
	if (album)  g_string_append_printf(msgstr, " on %s", album);
	g_string_append_printf(msgstr, " using XMMS2 :D\n");
	purple_debug_info(PLUGIN_ID, msgstr->str);
	
	set_savedstatus(msgstr);
	
	g_string_free(msgstr, TRUE);
}

void
xmms2_status_cb (xmmsc_result_t *result, void *userdata)
{
	if (!xmmsc_result_get_uint (result, &play_status)) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Error getting current playback status", "Please make sure XMMS2 is playing");
		return;
	}
	purple_debug_info(PLUGIN_ID, "current status %d\n", play_status);
	if (play_status != 1) {
		unset_status();
	} else {
		XMMS_CALLBACK_SET(xmms2conn, xmmsc_playback_current_id, update_song_idchange_cb, xmms2conn);
	}
}

void
info_changed_cb (xmmsc_result_t *result, void *userdata)
{
	unsigned int id;
	if (!display_song) return;
	
	if (!xmmsc_result_get_uint (result, &id)) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Could not retrieve current song (update_song_idchange_cb)", "Please make sure XMMS2 is playing");
		return;
	}
	
	if (id == current_song_id) {
		update_song_idchange_cb (result, userdata);
	}
}

static void
toggle_display_status_cb(PurplePluginAction *action)
{
	if (!xmms2_connected) {
		xmms2_connected = xmms2_connect();
		return;
	} else {
		display_song = !display_song;
		purple_debug_info(PLUGIN_ID, "toggle_display_status_cb: changing %d\n", display_song);
		if (display_song) {
			XMMS_CALLBACK_SET(xmms2conn, xmmsc_playback_status, xmms2_status_cb, xmms2conn)
		} else {
			unset_status();
		}
	}
}

static void
quitting_cb(void *data)
{
	unset_status();
}

static void
status_changed_cb(PurpleAccount *account, PurpleStatus *old, PurpleStatus *new, gpointer data)
{
	PurpleSavedStatus *current_savedstatus = purple_savedstatus_get_current();
	
	purple_debug_info(PLUGIN_ID, "got status changed: %s\n", purple_savedstatus_get_message(current_savedstatus));
	if (!display_song) return;
	if (strcmp("XMMS2", purple_savedstatus_get_title(current_savedstatus))) {
		XMMS_CALLBACK_SET(xmms2conn, xmmsc_playback_status, xmms2_status_cb, xmms2conn)
	}
}

/*
static void
get_current_song_cb(PurplePluginAction *action)
{
	xmmsc_result_t *result;
	unsigned int id;
	GString *msgstr = NULL;
	
	result = xmmsc_playback_current_id (xmms2conn);
	xmmsc_result_wait (result);
	
	if (xmmsc_result_iserror (result)) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Could not retrieve current song", "Please make sure XMMS2 is playing");
		return;
	}
	
	if (!xmmsc_result_get_uint (result, &id)) {
		purple_notify_error (xmms2_pidgin_plugin, "XMMS2 Pidgin Error",
			"Could not retrieve current song", "Please make sure XMMS2 is playing");
		return;
	}
	
	msgstr = g_string_new("");
	g_string_append_printf(msgstr, "The current song id is: %d", id);
	
	purple_notify_message(xmms2_pidgin_plugin, PURPLE_NOTIFY_MSG_INFO,
		"XMMS2 Pidgin", msgstr->str,
		NULL, NULL, NULL);
	
	g_string_free(msgstr, TRUE);
	xmmsc_result_unref (result);
}
*/

static GList *
plugin_actions(PurplePlugin *plugin, gpointer context)
{
    GList *list = NULL;
    PurplePluginAction *action = NULL;

    action = purple_plugin_action_new("Toggle displaying status", toggle_display_status_cb);

    list = g_list_append(list, action);

    return list;
}

static gboolean
xmms2_connect(void) {
	if (xmms2_connected) return TRUE;
	
	if (!(xmms2conn = xmmsc_init ("xmms2-pidgin"))) {
		purple_debug_info(PLUGIN_ID, "failed to connect\n");
		//purple_notify_error (plugin, "XMMS2 Pidgin Error",
		//	"Could not open a connection to XMMS2", "Please make sure XMMS2 is started");
		return FALSE;
	}
	if (!xmmsc_connect (xmms2conn, getenv ("XMMS_PATH"))) {
		purple_debug_info(PLUGIN_ID, "failed to connect\n");
		//purple_notify_error (plugin, "XMMS2 Pidgin Error",
		//	"Could not open a connection to XMMS2", "Please make sure XMMS2 is started");
		return FALSE;
	}
	
	xmmsc_mainloop_gmain_init (xmms2conn);
	
	XMMS_CALLBACK_SET(xmms2conn, xmmsc_playback_status, xmms2_status_cb, xmms2conn);
	XMMS_CALLBACK_SET(xmms2conn, xmmsc_broadcast_playback_current_id, update_song_idchange_cb, xmms2conn);
	XMMS_CALLBACK_SET(xmms2conn, xmmsc_broadcast_playback_status, xmms2_status_cb, xmms2conn);
	XMMS_CALLBACK_SET(xmms2conn, xmmsc_broadcast_medialib_entry_changed, info_changed_cb, xmms2conn);
	
	display_song = TRUE;

	return TRUE;
}

static gboolean
plugin_load(PurplePlugin *plugin) {
	void *core_handle = purple_get_core();
	void *accounts_handle = purple_accounts_get_handle();

	xmms2_connected = xmms2_connect();
	
	purple_signal_connect(core_handle, "quitting", plugin, PURPLE_CALLBACK(quitting_cb), NULL);
	purple_signal_connect(accounts_handle, "account-status-changed", plugin, PURPLE_CALLBACK(status_changed_cb), NULL);
	
	xmms2_pidgin_plugin = plugin;
	original_savedstatus = purple_savedstatus_get_current();

	return TRUE;
}

static gboolean
plugin_unload(PurplePlugin *plugin)
{
	xmmsc_unref (xmms2conn);
	
	return TRUE;
}

static PurplePluginInfo info = {
	PURPLE_PLUGIN_MAGIC,
	PURPLE_MAJOR_VERSION,
	PURPLE_MINOR_VERSION,
	PURPLE_PLUGIN_STANDARD,
	NULL,
	0,
	NULL,
	PURPLE_PRIORITY_DEFAULT,
	
	PLUGIN_ID,
	"XMMS2 Pidgin",
	"0.3",
	
	"Displays current XMMS2 song in status",
	"XMMS2 client that updates the status with the current song",
	"Jitu Das <jitudas@gmail.com>",
	"http://code.google.com/p/xmms2-pidgin/",
	
	plugin_load,
	plugin_unload,
	NULL,

	NULL,
	NULL,
	NULL,
	plugin_actions,
	NULL,
	NULL,
	NULL,
	NULL
};

static void
init_plugin(PurplePlugin *plugin)
{
}

PURPLE_INIT_PLUGIN(xmms2_pidgin, init_plugin, info)
